﻿Imports System.ComponentModel
Imports System.Xml.Serialization
Imports System.Runtime.Serialization
Imports System.Xml
Imports System.IO
Imports System.Text
<SerializableAttribute()> _
Public Class NDataTable
    Inherits MarshalByValueComponent
    Implements IListSource
    Implements IXmlSerializable
    Implements ISupportInitializeNotification
    Implements ISupportInitialize
    Implements ISerializable
    Implements IList(Of Dataitems)
#Region "Private"
    Private _recordcount As Integer = 0
    Private _list As System.Collections.Generic.IList(Of Dataitems)
    Private _status As Integer = 0
    Private _msg As String = ""
#End Region
#Region "Ctor"
    Public Sub New()
        _list = New System.Collections.Generic.List(Of Dataitems)
        _status = 0
        _msg = ""
        _recordcount = 0
    End Sub
    Public Sub New(s As SerializationInfo, c As StreamingContext)
        _recordcount = s.GetInt32("recordcount")
        _status = s.GetInt16("status")
        _msg = s.GetString("msg")
        Dim b As Byte() = CType(s.GetValue("list", GetType(Byte())), Byte())
        load(b)
    End Sub
#End Region
#Region "IListSource"
    Public ReadOnly Property ContainsListCollection As Boolean Implements IListSource.ContainsListCollection
        Get
            Return True
        End Get
    End Property

    Public Function GetList() As IList Implements IListSource.GetList
        Dim ml As New BindingList(Of Dataitems)
        If Not DesignMode Then
            For Each dit In _list
                ml.Add(dit)
            Next
        End If
        Return ml
    End Function
#End Region
#Region "IXmlSerializable"
    Public Function GetSchema() As Xml.Schema.XmlSchema Implements IXmlSerializable.GetSchema
        Return Nothing
    End Function

    Public Sub ReadXml(reader As Xml.XmlReader) Implements IXmlSerializable.ReadXml
        _list = New List(Of Dataitems)
        If reader.IsEmptyElement OrElse (Not reader.Read) Then
            Exit Sub
        End If
        Dim isItems As Boolean = False
        Dim ditem As Dataitems = Nothing
        While reader.Read
            Select Case reader.NodeType
                Case Xml.XmlNodeType.Element
                    If isItems = False Then
                        If reader.Name = "recordcount" Then
                            If reader.Read Then
                                _recordcount = CType(reader.Value, Integer)
                            End If
                        ElseIf reader.Name = "status" Then
                            If reader.Read Then
                                _status = CType(reader.Value, Integer)
                            End If
                        ElseIf reader.Name = "msg" Then
                            If reader.Read Then
                                _msg = reader.Value
                            End If

                        ElseIf reader.Name = "items" Then
                            ditem = New Dataitems()
                            isItems = True
                            'ElseIf reader.Name = "items" Then
                        End If
                    Else
                        If reader.Name = "items" Then
                            ditem = New Dataitems()
                        Else
                            Dim n As String = reader.Name
                            If reader.Read Then
                                ditem.Add(n, reader.Value)
                            End If
                        End If
                    End If
                    'If reader.Name = "items" Then
                    '    ditem.Add(reader.Name, reader.ReadElementContentAsString())
                    'End If
                Case XmlNodeType.Element
                    If isItems = False Then
                        If reader.Name = "items" Then
                            ditem = New Dataitems
                        End If
                    Else

                    End If
                  
                Case Xml.XmlNodeType.EndElement
                    If reader.Name = "items" Then
                        _list.Add(ditem)
                    End If
            End Select
        End While
    End Sub

    Public Sub WriteXml(writer As Xml.XmlWriter) Implements IXmlSerializable.WriteXml
        writer.WriteStartDocument()
        writer.WriteStartElement("ntable")
        writer.WriteStartElement("recordcount")
        writer.WriteValue(_recordcount.ToString())
        writer.WriteEndElement()
        writer.WriteStartElement("status")
        writer.WriteString(_status.ToString())
        writer.WriteEndElement()
        writer.WriteStartElement("msg")
        writer.WriteString(_msg)
        writer.WriteEndElement()
        For Each ditem In _list
            writer.WriteStartElement("items")
            For i As Integer = 0 To ditem.Count - 1
                writer.WriteStartElement(ditem.Item(i).Name)
                writer.WriteString(ditem.Items(i).Value)
                writer.WriteEndElement()
            Next
            writer.WriteEndElement()
        Next
        writer.WriteEndElement()
        writer.WriteEndDocument()
        writer.Flush()
        writer.Close()
    End Sub
#End Region
#Region "ISupportInitializeNotification"
    Public Sub BeginInit() Implements ISupportInitialize.BeginInit

    End Sub

    Public Sub EndInit() Implements ISupportInitialize.EndInit

    End Sub

    Public Event Initialized(sender As Object, e As EventArgs) Implements ISupportInitializeNotification.Initialized

    Public ReadOnly Property IsInitialized As Boolean Implements ISupportInitializeNotification.IsInitialized
        Get
            Return True
        End Get
    End Property
#End Region
#Region "ISerializable"
    Public Sub GetObjectData(info As SerializationInfo, context As StreamingContext) Implements ISerializable.GetObjectData
        info.AddValue("recordcount", _recordcount)
        info.AddValue("status", _status)
        info.AddValue("msg", _msg, GetType(String))
        info.AddValue("list", ToBytes(), GetType(Byte()))
    End Sub
#End Region
#Region "method"
    Public ReadOnly Property Items() As List(Of Dataitems)
        Get
            Return CType(_list, List(Of Dataitems))
        End Get
    End Property
    Public Sub Load(ByVal reader As IDataReader)
        If reader Is Nothing Then Exit Sub
        Dim l As Integer = reader.FieldCount
        Dim nL As New List(Of String)
        Try
            For i As Integer = 0 To l - 1
                nL.Add(reader.GetName(i))
            Next
            While reader.Read
                Dim items As New Dataitems
                For i As Integer = 0 To l - 1
                    Dim index As Integer = reader.GetOrdinal(nL.Item(i))
                    If (index > -1 AndAlso reader.GetValue(index) IsNot System.DBNull.Value) Then
                        items.Add(nL.Item(i), reader.GetValue(index))
                    Else
                        items.Add(nL.Item(i), "")
                    End If
                Next
                _list.Add(items)
            End While
            _recordcount = _list.Count
            _status = 1
            _msg = ""
        Catch ex As Exception
            _status = 0
            _msg = ex.Message
            Exit Try
        End Try
    End Sub
    Public Sub Load(ByVal str As String)
        If str Is Nothing OrElse str.Trim().Length = 0 Then Exit Sub
        Try
            Dim bytes As Byte() = System.Text.Encoding.UTF8.GetBytes(str.Trim())
            Load(bytes)
        Catch ex As Exception
            ' Throw New Exception(ex.Message)
            Exit Sub
        End Try
    End Sub
    Public Sub Load(ByVal bytes() As Byte)
        '  Try
        If bytes Is Nothing OrElse bytes.Length = 0 Then Exit Sub
        Dim s As Stream = New MemoryStream(bytes)
        Dim xrd As XmlReader = XmlReader.Create(s)
        ReadXml(xrd)
        '    Dim xmlr As XPathDocument = New XPathDocument(s)
        '    Dim nav As XPathNavigator = xmlr.CreateNavigator()
        '    Dim tp As XPathNodeIterator
        '    Dim items As Dataitems
        '    Dim cn = nav.SelectSingleNode("ntable/recordcount")
        '    If cn IsNot Nothing Then
        '        _recordCount = cn.ValueAsInt()
        '    End If
        '    cn = nav.SelectSingleNode("ntable/msg")
        '    If cn IsNot Nothing Then
        '        _msg = cn.Value
        '    End If
        '    For Each p As XPathNavigator In nav.Select("ntable/items")
        '        items = New Dataitems()
        '        tp = p.SelectDescendants(XPathNodeType.Element, False)
        '        While tp.MoveNext
        '            items.Add(tp.Current.Name, tp.Current.Value)
        '        End While
        '        _list.Add(items)
        '    Next
        '    _status = 1
        'Catch ex As Exception
        '    _status = 0
        '    _msg = ex.Message
        '    Exit Sub
        'End Try
    End Sub
    ''' <summary>
    ''' 将NDataTable 转化为XML格式String
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Overrides Function ToString() As String
        Dim sb As New StringBuilder()
        If _list.Count > 0 Then
            sb.Append("<?xml version=""1.0"" encoding=""utf-8"" ?>")
            sb.Append("<ntable>")
            sb.AppendFormat("<{0}>{1}</{0}>", "recordcount", _recordcount.ToString())
            sb.AppendFormat("<{0}>{1}</{0}>", "status", _status.ToString())
            sb.AppendFormat("<{0}>{1}</{0}>", "msg", _msg.ToString())
            For i As Integer = 0 To _list.Count - 1
                sb.Append("<items>")
                For j As Integer = 0 To _list.Item(i).Count - 1
                    sb.Append(String.Format("<{0}><![CDATA[{1}]]></{0}>", _list.Item(i).Item(j).Name, _list.Item(i).Item(j).Value))
                Next
                sb.Append("</items>")
            Next
            sb.Append("</ntable>")
        End If
        Return sb.ToString()
    End Function
    ''' <summary>
    ''' 转化为Bytes
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function ToBytes() As Byte()
        Using tstr As New System.IO.MemoryStream()
            Dim xset As XmlWriterSettings = New XmlWriterSettings()
            xset.Encoding = Encoding.UTF8
            xset.CloseOutput = False
            Dim xwr As XmlWriter = XmlWriter.Create(tstr, xset)
            WriteXml(xwr)
            tstr.Position = 0
            Return tstr.ToArray()
        End Using
        ' Return System.Text.Encoding.UTF8.GetBytes(ToString())
    End Function
#End Region
#Region "IList"
    Public Sub Add(item As Dataitems) Implements ICollection(Of Dataitems).Add
        _list.Add(item)
    End Sub

    Public Sub Clear() Implements ICollection(Of Dataitems).Clear
        _list.Clear()
    End Sub

    Public Function Contains(item As Dataitems) As Boolean Implements ICollection(Of Dataitems).Contains
        Return _list.Contains(item)
    End Function

    Public Sub CopyTo(array() As Dataitems, arrayIndex As Integer) Implements ICollection(Of Dataitems).CopyTo
        _list.CopyTo(array, arrayIndex)
    End Sub

    Public ReadOnly Property Count As Integer Implements ICollection(Of Dataitems).Count
        Get
            Return _list.Count
        End Get
    End Property

    Public ReadOnly Property IsReadOnly As Boolean Implements ICollection(Of Dataitems).IsReadOnly
        Get
            Return False
        End Get
    End Property

    Public Function Remove(item As Dataitems) As Boolean Implements ICollection(Of Dataitems).Remove
        Return _list.Remove(item)
    End Function

    Public Iterator Function GetEnumerator() As IEnumerator(Of Dataitems) Implements IEnumerable(Of Dataitems).GetEnumerator
        For Each it In _list
            Yield it
        Next
    End Function

    Public Function IndexOf(item As Dataitems) As Integer Implements IList(Of Dataitems).IndexOf
        Return _list.IndexOf(item)
    End Function

    Public Sub Insert(index As Integer, item As Dataitems) Implements IList(Of Dataitems).Insert
        _list.Insert(index, item)
    End Sub

    Default Public Property Item(index As Integer) As Dataitems Implements IList(Of Dataitems).Item
        Get
            If index < 0 OrElse index > _list.Count - 1 Then
                index = 0
            End If
            Return _list(index)
        End Get
        Set(value As Dataitems)

        End Set
    End Property

    Public Sub RemoveAt(index As Integer) Implements IList(Of Dataitems).RemoveAt
        _list.RemoveAt(index)
    End Sub

    Public Function GetEnumerator1() As IEnumerator Implements IEnumerable.GetEnumerator
        Return GetEnumerator()
    End Function
#End Region
End Class
<Serializable()> _
Public NotInheritable Class Dataitems
    Implements ISerializable
    Private mList As List(Of DataValues)
    Public Sub New()
        mList = New List(Of DataValues)
    End Sub
    Public Sub Add(Of T)(ByVal [name] As String, ByVal [value] As T)
        mList.Add(New DataValues([name], value.ToString()))
    End Sub
    Public Sub Add(ByVal [name] As String, ByVal [value] As String)
        mList.Add(New DataValues([name], [value]))
    End Sub
    Public Sub Insert(ByVal i As Integer, ByVal [name] As String, ByVal [value] As String)
        mList.Insert(i, New DataValues([name], [value].ToString()))
    End Sub
    Default ReadOnly Property Item(ByVal [name] As String) As DataValues
        Get
            Dim v As DataValues = Nothing
            For i As Integer = 0 To mList.Count - 1
                If mList.Item(i).Name.Equals([name], StringComparison.CurrentCultureIgnoreCase) Then
                    v = mList.Item(i)
                    Exit For
                End If
            Next
            If v Is Nothing Then v = New DataValues([name], String.Empty)
            Return v
        End Get
    End Property
    Public ReadOnly Property Items() As Dataitems
        Get
            Return Me
        End Get
    End Property
    Default ReadOnly Property Item(ByVal index As Integer) As DataValues
        Get
            If index > mList.Count - 1 OrElse index < 0 Then
                Throw New IndexOutOfRangeException("索引超出范围")
            Else
                Return mList.Item(index)
            End If
        End Get
    End Property

    Public Function GetValue(ByVal [name] As String) As String
        Dim v As String = ""
        For i As Integer = 0 To mList.Count - 1
            If mList.Item(i).Name.Equals([name]) Then
                v = mList.Item(i).Value
                Exit For
            End If
        Next
        Return v
    End Function


   
    Public ReadOnly Property Count() As Integer
        Get
            Return mList.Count
        End Get
    End Property
    Public Overrides Function ToString() As String
        Dim sb As New StringBuilder()
        If mList.Count > 0 Then
            sb.Append("<items>")
            For i As Integer = 0 To mList.Count - 1
                sb.Append(String.Format("<{0}><![CDATA[{1}]]></{0}>", mList.Item(i).Name, mList.Item(i).ToString()))
            Next
            sb.Append("</items>")
        End If
        Return sb.ToString()
    End Function
    Public Sub New(info As SerializationInfo, context As StreamingContext)
        mList = CType(info.GetValue("mlist", GetType(List(Of DataValues))), List(Of DataValues))
    End Sub

    Public Sub GetObjectData(info As System.Runtime.Serialization.SerializationInfo, context As System.Runtime.Serialization.StreamingContext) Implements System.Runtime.Serialization.ISerializable.GetObjectData
        info.AddValue("mlist", mList, GetType(List(Of DataValues)))
    End Sub
End Class
<Serializable()> _
Public NotInheritable Class DataValues
    Implements ISerializable
    Private mName As StringBuilder = Nothing
    Private mValue As StringBuilder = Nothing
    ''' <summary>
    ''' Name
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property Name() As String
        Get
            If mName Is Nothing Then
                Return ""
            Else
                Return mName.ToString()
            End If
        End Get
        Set(ByVal value As String)
            mName = New StringBuilder()
            mName.Append(value)
        End Set
    End Property
    ''' <summary>
    ''' 值
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property Value() As String
        Get
            If mValue Is Nothing Then
                Return ""
            Else
                Return mValue.ToString()
            End If
        End Get
        Set(ByVal value As String)
            mValue = New StringBuilder()
            mValue.Append(value)
        End Set
    End Property

    Public Overrides Function ToString() As String
        If mValue Is Nothing Then
            Return ""
        Else
            Return mValue.ToString()
        End If
    End Function

    Public Sub New(ByVal [name] As String, ByVal [value] As String)
        mName = New StringBuilder()
        mValue = New StringBuilder()
        '  mtype = New StringBuilder()
        mName.Append(name)
        mValue.Append([value])
    End Sub
    Public Sub New(info As SerializationInfo, context As StreamingContext)
        MyClass.New(info.GetString("Name"), info.GetString("Value"))
    End Sub
    Public Sub GetObjectData(info As System.Runtime.Serialization.SerializationInfo, context As System.Runtime.Serialization.StreamingContext) Implements System.Runtime.Serialization.ISerializable.GetObjectData
        info.AddValue("Name", Name)
        info.AddValue("Value", Value)
    End Sub
End Class